home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 6 / QRZ Ham Radio Callsign Database - Volume 6.iso / pc / files / finland / ddlcpack.lzh / DDLC.C next >
Encoding:
C/C++ Source or Header  |  1993-01-06  |  45.5 KB  |  1,447 lines

  1. /*
  2.  * Interface driver for the OH1MQK Dual-DDLC (MC145488) card
  3.  * Copyright 1992 by Matti Aarnio, OH1MQK  ( Internet: mea@utu.fi )
  4.  *  Permission for non-commercial use is hereby granted provided
  5.  *  this notice is retained.  For info call +358-21-854717,
  6.  *  or preferrably reach via the Internet...
  7.  *
  8.  * Portions of this driver were derived from the HAPN-card driver
  9.  * by Jon Bloom, KE3Z, SCC-card driver by PE1CHL and KY3B, and
  10.  * PI-card driver by Dave Perry, VE3IFB, as well as some code by
  11.  * Phil Karn, KA9Q...
  12.  * (Yeah, I had to look for some model to write this :-) )
  13.  *
  14.  *
  15.  * Affected files:
  16.  *   ddlc.c ddlc.h ddlc.doc rawhdlc.h rawhdlc.c ddlcvec.asm  (NEW!)
  17.  *   commands.h config.h config.c makefile pc.tl internet.tl
  18.  */
  19.  
  20. #include <time.h>
  21. #include <stdio.h>
  22. #include <dos.h>
  23. #include <bios.h>
  24. #include "global.h"
  25. #include "mbuf.h"
  26. #include "iface.h"
  27. #include "pktdrvr.h"
  28. #include "netuser.h"
  29. #include "ddlc.h"
  30.  
  31. #ifdef AX25 /* Works also w/o AX.25 ! */
  32. #include "ax25.h"
  33. #endif
  34.  
  35. #include "trace.h"
  36. #include "pc.h"
  37.  
  38. #include "session.h"
  39. #include "lapb.h"
  40. #include "proc.h"
  41. #include "ip.h"
  42. #include "devparam.h"
  43.  
  44. #ifndef FP_OFF
  45. #define FP_OFF(fp)    ((unsigned)(fp))
  46. #endif
  47. #ifndef FP_SEG
  48. #define FP_SEG(fp)    ((unsigned)((unsigned long)(fp) >> 16))
  49. #endif
  50. #define BUF_IN_USE 0x8000
  51. #define CONFIGREG  0x0180 /* Offset to config register */
  52. #define MEMSTART   0x0200 /* Offset to begin of memory */
  53. #define DTRREG     0x0100 /* Offset to DTR/SCPENA/.. -register */
  54.  
  55.  
  56. /*INTERRUPT (far *(ddlcint) __ARGS((int dev)))();*/
  57. extern void  ddlcint    __ARGS((int16 dev));
  58. static int32 ddlc_ctl    __ARGS((struct iface *iface,int cmd,int set,int32 val));
  59. static int   ddlc_raw    __ARGS((struct iface *iface,struct mbuf *bp));
  60. static int   ddlc_stop    __ARGS((struct iface *iface));
  61. static void  ddlc_rts    __ARGS((struct ddlcchan *ddch, int16 x));
  62. /*static void  setup_ddlc_rx_dma __ARGS((struct ddlcchan *ddch));
  63.   static void  setup_ddlc_tx_dma __ARGS((struct ddlcchan *ddch, char *buffer,
  64.                        int length)); */
  65. static void  ddlc_buf_combiner __ARGS((struct ddlcchan *ddch));
  66. static void  ddlc_buf_free __ARGS((const char *buf));
  67. static char *ddlc_buf_alloc __ARGS((struct ddlcchan *ddch, const int extra));
  68. static void  ddlc_buf_purge __ARGS((struct ddlcchan *ddch));
  69. static void  ddlc_scpcomplete __ARGS((DDLC far *ddev,
  70.                       const int channel, const int data_ok));
  71. static void  ddlc_timerirq __ARGS((DDLC far *ddev,
  72.                    const int channel, const int data_ok));
  73. static void  tdelay    __ARGS((register struct ddlcchan *ddch,
  74.                 unsigned int time));
  75. static int   ddlc_init    __ARGS((const int boardnum, char far *boardbase,
  76.                 const int ivec, unsigned int memsize));
  77. static void  chipint    __ARGS((int dev, char far *boardbase, int chip,
  78.                 int IrqVal));
  79. static void  ddlc_abort __ARGS((const int IrqVal, const int channel));
  80. static void  ddlc_rxint    __ARGS((DDLC far *ddev,
  81.                 const int channel, const int data_ok));
  82. static void  ddlc_txint    __ARGS((DDLC far *ddev,
  83.                 const int channel, const int data_ok));
  84. static void  ddlc_txintdefer __ARGS((struct ddlcchan far * ddch));
  85. static int   cdchk    __ARGS((const DDLC *ddev, const int channel));
  86.  
  87. static struct DDLCTAB Ddlc[DDLCMAX];    /* Device table - one entry per card */
  88. /* This assumes that DDLCMAX == 2 */
  89. #if    (DDLCMAX == 2) /* Yup, Ddlc_handle[]-array will be missing if you
  90.               change DDLCMAX without proper re-write at necessary
  91.               places for multi-board operation.  Alike here...
  92.               Remember to edit DDLCVEC.ASM too! */
  93. static INTERRUPT (*Ddlc_handle[])() = {    /* handler interrupt vector table */
  94.     ddlc0vec,
  95.     ddlc1vec
  96. };
  97. #endif
  98.  
  99. static struct ddlcchan Ddlcchan[DDLCCMAX];    /* channel table - max 4 entries per card */
  100. static int    boardcnt = 0;
  101.  
  102.  
  103. #define CGETPUTW 1
  104. #ifdef CGETPUTW
  105. /* KLUDGE:  cgetw(), cputw() are for accessing DDLC chip registers, as
  106.         the DDLC-chip latches address lines at the start of /CS signal,
  107.         and does not pay attention to them while /WR or /RW are going
  108.         down & up.  Thus a 16-bit access will fail without following
  109.         cludge.  Access to SRAM works all right without this.  */
  110.  
  111. static unsigned int  cgetw __ARGS((const void far *addr));
  112.  
  113. static unsigned int  cgetw(addr)
  114. const void far *addr;
  115. {
  116.     asm les bx,dword ptr  addr    ;
  117.     asm mov al,byte ptr es:[bx+0]    ;
  118.     asm mov ah,byte ptr es:[bx+MEMSTART]; /* Spend a moment with RAM buffer */
  119.     asm mov ah,byte ptr es:[bx+1]    ;
  120.     return _AX;
  121. }
  122.  
  123. static void cputw __ARGS((const void far *addr, const unsigned int val));
  124.  
  125. static void cputw(addr,val)
  126. const void far *addr; const unsigned int val;
  127. {
  128.     asm les bx,dword ptr  addr    ;
  129.     asm mov ax,word ptr  val    ;
  130.     asm mov byte ptr es:[bx+0],al    ;
  131.     asm mov al,byte ptr es:[bx+MEMSTART]; /* Spend a moment with RAM buffer */
  132.     asm mov byte ptr es:[bx+1],ah    ;
  133. }
  134. #else
  135. #define cgetw(addr)    (*(int16*)addr)
  136. #define cputw(addr,val) (*(int16*)addr=(int16)val)
  137. #endif
  138.  
  139.  
  140. /* Interrupt vector is directed here, ddlc#vec feeds argument for this
  141.    board-level interrupt master dispatcher */
  142. void
  143. ddlcint(dev)
  144. int16 dev;
  145. {
  146.     char far *Board = Ddlc[dev].boardbase;
  147.     int doagain = 1;
  148.     int Mstr    = 0;
  149.  
  150.     while (doagain) {
  151.         doagain = 0;
  152.         if (Ddlc[dev].channelcnt == 2) {
  153.             Mstr = ((DDLC *)Board)[1].MStat.mstr_stat.VecNum;
  154.             if (Mstr != 0) {
  155.                 /* Channels 2 & 3 */
  156.                 chipint(dev,Board,1,Mstr);
  157.                 doagain = 1;
  158.             }
  159.         }
  160.         Mstr = ((DDLC *)Board)[0].MStat.mstr_stat.VecNum;
  161.         if (Mstr != 0) {
  162.             /* Channels 0 & 1 */
  163.             chipint(dev,Board,0,Mstr);
  164.             doagain = 1;
  165.         }
  166.     }
  167. }
  168.  
  169.  
  170. /* chipint()    Now we know which of the two chips the interrupt came from,
  171.         analyze more deeply. */
  172. static void
  173. chipint(dev, boardbase, chip, IrqVal)
  174. int dev; /* Actually board reference - not channel reference! */
  175. char far *boardbase;
  176. int chip;
  177. int IrqVal;
  178. {
  179.     int channel =    dev * CHANNELS_ON_BOARD +
  180.             chip * 2; /* This one or the next channel */
  181.     DDLC *ddev = (DDLC*)((long)boardbase + chip * sizeof(DDLC));
  182.     switch(IrqVal) {
  183.         case  2: /* SCP Complete  -- XX: not used at present */
  184.             ddlc_scpcomplete(ddev,channel,TRUE);
  185.             break;
  186.         case  1: /* Channel 0 TIMER interrupt   XX: not used at present */
  187.             ddlc_timerirq(ddev,channel+0,TRUE);
  188.             break;
  189.         case  3: /* Channel 1 TIMER interrupt   XX: not used at present */
  190.             ddlc_timerirq(ddev,channel+1,TRUE);
  191.             break;
  192.         case  4: /* Channel 0 bit handler normal receiver */
  193.             ddlc_rxint(ddev,channel+0,TRUE);
  194.             break;
  195.         case  5: /* Channel 0 bit handler normal transmitter */
  196.             ddlc_txint(ddev,channel+0,TRUE);
  197.             break;
  198.         case  6: /* Channel 1 bit handler normal receiver */
  199.             ddlc_rxint(ddev,channel+1,TRUE);
  200.             break;
  201.         case  7: /* Channel 1 bit handler normal transmitter */
  202.             ddlc_txint(ddev,channel+1,TRUE);
  203.             break;
  204.         case  8: /* Channel 0 bit handler fault receiver */
  205.             ddlc_rxint(ddev,channel+0,FALSE);
  206.             break;
  207.         case  9: /* Channel 0 bit handler fault transmitter */
  208.             ddlc_txint(ddev,channel+1,FALSE);
  209.             break;
  210.         case 10: /* Channel 1 bit handler fault receiver */
  211.             ddlc_rxint(ddev,channel+1,FALSE);
  212.             break;
  213.         case 11: /* Channel 1 bit handler fault transmitter */
  214.             ddlc_txint(ddev,channel+1,FALSE);
  215.             break;
  216.         case 12: case 13: case 14: case 15: /* System fault! */
  217.             /* Address errors, etc. If so, can't happen with
  218.                the DDLC-card.  */
  219.             ddlc_abort(IrqVal, channel);
  220.             break;
  221.         default: /* 0: No (more) interrupt.. */
  222.             break;
  223.     }
  224. }
  225.  
  226.  
  227. static void
  228. ddlc_scpcomplete(ddev,channel,data_ok) /* XX: not used at present */
  229. DDLC far *ddev;
  230. const int channel;
  231. const int data_ok;
  232. {
  233.     return;
  234. }
  235.  
  236.  
  237. static void
  238. ddlc_timerirq(ddev,channel,data_ok) /* XX: not used at present */
  239. DDLC far *ddev;
  240. const int channel;
  241. const int data_ok;
  242. {
  243.     return;
  244. }
  245.  
  246.  
  247. /*  test for busy channel (CD active)
  248.  *  returns TRUE if channel busy
  249.  */
  250. static int
  251. cdchk(ddev,channel)
  252. const DDLC *ddev;
  253. const int channel;
  254. {
  255.     return ddev[1 & (channel >> 1)].    \
  256.         Ch_Regs[channel & 1].        \
  257.          RxStat.rx_status.CD;
  258. }
  259.  
  260.  
  261. static void
  262. ddlc_abort(IrqVal, channel)
  263. const int IrqVal, channel;
  264. {
  265.     /* Foo! Got some system fault from the devices.
  266.        Flush the buffers, and kill the interface -- ddlc_stop() */
  267.  
  268.     struct ddlcchan *ddch  = & Ddlcchan[ channel ];
  269.  
  270.     if (IrqVal & 2) /* Channel 1, not 0, within the chip. */
  271.         ++ddch;
  272.  
  273.     if_detach(ddch->iface);
  274.     ddch->iface = NULL; /* if_detach() does free() to that structure.. */
  275. }
  276.  
  277.  
  278. /* Buffer management scheme:
  279.  
  280.    Every channel has TWO INCOMING, and TWO OUTGOING buffers.
  281.  
  282.    Buffers are allocated for MTU-size only.  Max MTU for all
  283.    channels at the board is circa 1kB for 16kB board, and 2kB
  284.    for 32kB board.  (Assuming all channels use same MTU value..)
  285.    Of course total usage can not exceed free buffer memory.
  286.    Single used channel can utilize whole buffer for itself,
  287.    however: buffer length registers are 12 bits only, thus max
  288.    buffer size is 4kB.
  289.  
  290.    Buffer usage (both xmit and rcv) is a typical dual-buffer
  291.    scheme.  Fill/empty a buffer while another is being
  292.    sent/received.
  293.  
  294.    Buffer allocation is done in the attach order, but buffer re-use
  295.    after detach of a channel is possible.
  296.  
  297. */
  298.  
  299.  
  300.  
  301. /* Buffer allocation scheme:
  302.     <16bit word> -- bit15:     1-> in use, 0-> free
  303.             bits0..14: size of buffer in bytes
  304.             (When 0, no other buffer follows, this is the last)
  305.     <size bytes> -- buffer
  306.  
  307.    When a buffer is allocated, its size is stored in the header word,
  308.    and a pointer is returned to the actual buffer.
  309.  
  310.    Buffer freeing clears bit15, and starts to combine free buffers
  311.    into one larger - to ease fragmentation. If free buffer is last,
  312.    it is blown out alltogether, and  nextfreebuf it set to it.
  313.  
  314.  
  315.    NOTE: This is used only with   `attach'  and  `detach'  commands,
  316.      never elsewere !  No need for high speed...
  317. */
  318.  
  319.  
  320. /* Allocate buffer, all necessary info is taken from channel structure
  321.    datas.   If extra bytes are needed - receive buffer CRC storage for
  322.    example - remember to request appropriate extras */
  323. static char *
  324. ddlc_buf_alloc(ddch,extra)
  325. struct ddlcchan *ddch;
  326. const int extra;
  327. {
  328.     char  *buf    = NULL;
  329.     int16 *blk, *blocks = (int16*) (ddch->Board->boardbase + MEMSTART),
  330.             *memend = (int16*) (ddch->Board->boardbase + ddch->Board->boardsize);
  331.  
  332.      int   allocsize = (ddch->bufsiz + extra);
  333.     int16 sizflag;
  334.  
  335.     if (allocsize & 1) ++allocsize; /* Even number of bytes.. */
  336.     sizflag = (unsigned)(BUF_IN_USE | allocsize);
  337.  
  338.  
  339.     /* Leave when no more allocated buffer blocks are in store */
  340.     while ((*blocks != 0) && (blocks < memend)) {
  341.         while ((*blocks & BUF_IN_USE) && (blocks < memend)) {
  342.             (char*)blocks += ((*blocks & ~BUF_IN_USE) + 2);
  343.         }
  344.         if (!*blocks) break;
  345.         /* Some free buffer block, split it if large enough */
  346.         if (*blocks >= (allocsize + 2 + 66)) { /* Can be split (usefully) */
  347.             /* Mark splice place higer up in the memory */
  348.             buf = (char*)blocks;
  349.             blk  = (int16*)(buf+2+allocsize);
  350.             *blk = *blocks - (2 + allocsize);
  351.             *blocks = sizflag;
  352.             break;
  353.         }
  354.         if (*blocks >= allocsize) { /* Tight fit */
  355.             buf = (char*)blocks;
  356.             *blocks |= BUF_IN_USE;
  357.             break;
  358.         }
  359.         /* Not large enough block, scan forwards.. */
  360.         (char*)blocks += ((*blocks & ~BUF_IN_USE) + 2);
  361.     }
  362.     /* End of buffers..
  363.        Pick next from  nextfreebuf */
  364.  
  365.     /* Enlarge the heap */
  366.     if (!buf) { /* `blocks' points to the last buffer - null+2 size */
  367.         buf = (char*)blocks;
  368.         *blocks = sizflag;
  369.         /* Make sure next pointed entry is 0 size.. */
  370.         *(int16*)(buf+2+allocsize) = 0;
  371.     }
  372.     if (buf > ddch->Board->nextfreebuf) {
  373.         ddch->Board->nextfreebuf = buf + 2 + allocsize;
  374.         ddch->Board->bufavail = (char*)memend - (buf+2+allocsize+2);
  375.         if (ddch->Board->bufavail < 0) {
  376.             ddch->Board->bufavail = (char*)memend - (buf+2);
  377.             *blocks = 0;
  378.             return NULL;
  379.         }
  380.     }
  381.     return (buf+2);
  382. }
  383.  
  384. /* Cleaning up allocated buffers for possible later re-use. */
  385. static void
  386. ddlc_buf_combiner(ddch)
  387. struct ddlcchan *ddch;
  388. {
  389.     int16    *blocks = (int16*) (ddch->Board->boardbase + MEMSTART),
  390.         *memend = (int16*) (ddch->Board->boardbase + ddch->Board->boardsize);
  391.     int16     nextsiz, thissize;
  392.  
  393.     /* Leave when last buffer seen/combined/truncated */
  394.     while (*blocks && (blocks < memend)) {
  395.         /* Skip buffers in use */
  396.         while ((BUF_IN_USE & *blocks) && (blocks < memend)) {
  397.             (char*)blocks += (((*blocks) & ~BUF_IN_USE) +2);
  398.         }
  399.         if (!*blocks) break; /* Empty - that is, no buffer there */
  400.  
  401.         /* Now points at a free buffer */
  402.         thissize = (*blocks) & ~BUF_IN_USE;
  403.         if (thissize)
  404.             nextsiz = *(int16*)((char*)blocks + thissize +2);
  405.         else
  406.             nextsiz = 0;
  407.  
  408.         while ( thissize != 0 && nextsiz != 0 &&
  409.             !(nextsiz & BUF_IN_USE) && blocks < memend) {
  410.             /* (Possibly) intermediate free buffers, combine */
  411.             *blocks += (nextsiz +2);
  412.             thissize = (*blocks) & ~BUF_IN_USE;
  413.             if (thissize)
  414.                 nextsiz = *(int16*)((char*)blocks + thissize +2);
  415.             else
  416.                 nextsiz = 0;
  417.         }
  418.         if (!(*blocks & BUF_IN_USE) && (thissize == 0 || nextsiz == 0)) {
  419.             /* Last buffer - and free!
  420.                Truncate the heap */
  421.             ddch->Board->nextfreebuf = (char*)blocks;
  422.             ddch->Board->bufavail   += ((*blocks) +2);
  423.             *blocks = 0;
  424.             continue;
  425.         }
  426.         /*if (BUF_IN_USE & nextsiz)*/
  427.         (char*)blocks += (thissize +2);
  428.     }
  429. }
  430.  
  431. /* Freeing buffer is simple, mark it free.
  432.    Later run combiner to crunch them all.. */
  433. static void
  434. ddlc_buf_free(buf)
  435. const char *buf;
  436. {
  437.     int16 *blk;
  438.     blk   = (int16*)(buf -2);
  439.     *blk &= ~BUF_IN_USE;
  440. }
  441.  
  442. /* Well, do a block freeup, and then combine.. */
  443. static void
  444. ddlc_buf_purge(ddch)
  445. struct ddlcchan *ddch;
  446. {
  447.     if (ddch->rcp1)
  448.         ddlc_buf_free(ddch->rcp1);
  449.     ddch->rcp1 = NULL;
  450.     if (ddch->rcp2)
  451.         ddlc_buf_free(ddch->rcp2);
  452.     ddch->rcp2 = NULL;
  453.     if (ddch->txp1)
  454.         ddlc_buf_free(ddch->txp1);
  455.     ddch->txp1 = NULL;
  456.     if (ddch->txp2)
  457.         ddlc_buf_free(ddch->txp2);
  458.     ddch->txp2 = NULL;
  459.     ddlc_buf_combiner(ddch);
  460. }
  461.  
  462.  
  463.  
  464.  
  465.  
  466. /* INTERRUPT:   Classified as transmit interrupt,
  467.                 queue more material for transmit, or whatever.. */
  468. static void
  469. ddlc_txint(ddev, channel, data_ok)
  470. DDLC far *ddev;
  471. const int channel;
  472. const int data_ok;
  473. {
  474.         /* Material in the send queue and Tx is idle, or the DDLC-
  475.            chip Tx-unit gave an interrupt for some reason (Xmit done?) */
  476.         struct ddlcchan * ddch;
  477.         CH_REGS *chregs;
  478.         int16 len;
  479.  
  480.         ddch   = & Ddlcchan[channel];
  481.         chregs = & ddev->Ch_Regs[channel & 1];
  482.  
  483.         /* If  data_ok  is not negative, this is an acknowledge
  484.            of sent frame, get more from queue, if there is anything
  485.            to be sent..  */
  486.  
  487.         if (data_ok >= 0)
  488.                 ddch->txints++;
  489. /* XX:  Process Tx interrupt, and queue a datagram..    */
  490. /*      Frame complete  vs.  DMA complete ?             */
  491.  
  492.         if (data_ok >= 0)
  493.                 ddch->txside = !ddch->txside;
  494.  
  495. /* XX: Transmit routines...  all fun tricks for sync operations.. */
  496. /* XX: Delays for half-duplex ??? */
  497.  
  498.         /* Queue next packet for transmit, and initiate it */
  499.         if (ddch->txside == 0) {
  500.                 /* Prepare buffer, and initiate it for transfer */
  501.                 len = len_p(ddch->sndq);
  502.                 pullup((void*)ddch->sndq,(void*)ddch->txp1,len);
  503.                 cputw(&chregs->TxBase,  ddch->TxAbase);
  504.                 cputw(&chregs->TxFrLen, len);
  505.                 chregs->TxCont.tx_control.BR = 1;
  506.                 chregs->TxStat.tx_stat.TDC = 0; /* Either TDC or TFC, */
  507.                 chregs->TxStat.tx_stat.TFC = 0; /* zero both..        */
  508.         } else {
  509.                 /* Prepare buffer, and initiate it for transfer */
  510.                 len = len_p(ddch->sndq);
  511.                 pullup((void*)ddch->sndq,(void*)ddch->txp2,len);
  512.                 cputw(&chregs->TxBase,  ddch->TxBbase);
  513.                 cputw(&chregs->TxFrLen, len);
  514.                 chregs->TxCont.tx_control.BR = 1;
  515.                 chregs->TxStat.tx_stat.TDC = 0; /* Either TDC or TFC, */
  516.                 chregs->TxStat.tx_stat.TFC = 0; /* zero both..        */
  517.         }
  518. /* XX: Any more of these fancy things -- like TxDELAY, etc features ? */
  519. }
  520.  
  521. static void
  522. ddlc_txintdefer(ddch)
  523. struct ddlcchan *ddch;
  524. {
  525.         int channel    = ddch->dev;
  526.         int subchannel = ddch->unit;
  527.         DDLC *ddev     = &((DDLC*)ddch->Board->boardbase)[subchannel >> 1];
  528.  
  529.         ddlc_txint(ddev,channel,-1);
  530. }
  531.  
  532.  
  533.  
  534. /* INTERRUPT:   Classified as receiver interrupt, handle incoming
  535.                 packet.  */
  536. static void
  537. ddlc_rxint(ddev, channel, data_ok)
  538. DDLC far *ddev;
  539. const int channel;
  540. const int data_ok;
  541. {
  542.         struct ddlcchan * ddch = &Ddlcchan[channel];
  543.         CH_REGS *ddevch = & ddev->Ch_Regs[channel & 1];
  544.         int16 framesize;
  545.         struct mbuf *buf;
  546.  
  547.         /* Process incoming frame(s) */
  548.  
  549.         DISABLE(); /* ?? really necessary ? */
  550.  
  551.         ddch->rxints++;
  552.  
  553.         /* If present rxside is 0, activate buffer B, then continue with
  554.            handling the data in block A.  Else A and B :)                */
  555.         if (ddch->rxside == 0) {
  556.                 /* Buffer B to be activated */
  557.                 ddevch->RxCont.rx_control.BBR = 1;
  558.                 ddevch->RxCont.rx_control.BBR = 0;
  559.         } else {
  560.                 /* Buffer A to be activated */
  561.                 ddevch->RxCont.rx_control.BAR = 1;
  562.                 ddevch->RxCont.rx_control.BAR = 0;
  563.         }
  564.  
  565.         /* Do both (A and B buffer) checks, alter order depending on
  566.            what is the value of the side indicator (0 or 1) */
  567.  
  568.         if ((ddch->rxside == 0) &&
  569.             ddevch->RxStat.rx_status.RAC /* Buf A receive complete */) {
  570.                 if (data_ok) {
  571.                     /* received byte count includes 2 CRC bytes */
  572.                     framesize = cgetw(&ddevch->RxAByteCnt) - 2;
  573.                     buf = alloc_mbuf(framesize + sizeof(struct iface *));
  574.                     memcpy(buf->data+sizeof(struct iface *),
  575.                            ddch->rcp1,
  576.                            framesize);
  577.                     buf->cnt = framesize;
  578.                     net_route(ddch->iface, buf);
  579.                     ddch->rxframes++;
  580.                 }
  581.                 ddevch->RxStat.rx_status.RAC = 0;
  582.         }
  583.         if ((ddch->rxside != 0) &&
  584.             ddevch->RxStat.rx_status.RBC /* Buf B receive complete */) {
  585.                 if (data_ok) {
  586.                     /* received byte count includes 2 CRC bytes */
  587.                     framesize = cgetw(&ddevch->RxBByteCnt) - 2;
  588.                     buf = alloc_mbuf(framesize + sizeof(struct iface *));
  589.                     memcpy(buf->data+sizeof(struct iface *),
  590.                            ddch->rcp2,
  591.                            framesize);
  592.                     buf->cnt = framesize;
  593.                     net_route(ddch->iface, buf);
  594.                     ddch->rxframes++;
  595.                 }
  596.                 ddevch->RxStat.rx_status.RBC = 0;
  597.         }
  598.  
  599.         ddch->rxside = !ddch->rxside; /* Toggle side indicator value */
  600.         RESTORE(); /* ?? Really necessary ? */
  601. }
  602.  
  603.  
  604. /* ---------------------------------------------------------------- */
  605.  
  606. /* ddlc_init() -- initialize board for channel attach operations. */
  607.  
  608.  
  609. static int
  610. ddlc_init(boardnum, boardbase, ivec, memsize)
  611. const int  boardnum;
  612. char far *boardbase;
  613. const int  ivec;
  614. unsigned int memsize;
  615. {
  616.         DDLC *ddev = (DDLC*)boardbase;
  617.         int initcnt = 2;
  618.         int nchips  = 0; /* Assume it has 2 chips, trust to find only 1.. */
  619.         int timecount, ok;
  620.         int cfgval;
  621.  
  622.         /* Disable all operations of the board, enable proper
  623.            IRQs for operation, etc.. */
  624.  
  625.         ok = 1;
  626.         while(initcnt--) {
  627.                 /* Do SW RESET of the chip */
  628.                 timecount = 2000;   /*  Max time should be 512 clock cycles
  629.                                         at 14.xx MHz... Under normal conditions
  630.                                         this counter does not have time to
  631.                                         count at all! */
  632.                 ddev->System.sys_control.RESET = 1;
  633.                 while (ddev->System.sys_control.RESET && --timecount)
  634.                         ; /* Wait it to finish */
  635.                 if (timecount == 0) ok = 0;
  636.  
  637.                 /* Test some reset clearable register location - at first
  638.                    by storing there a bit-pattern and then reading it back,
  639.                    issue RESET, look again.  If fails, then claim an error */
  640.  
  641.                 ddev->Ch_Regs[0].AddCmp.AddrComp0 = 0xAA;
  642.                 if (ddev->Ch_Regs[0].AddCmp.AddrComp0 != 0xAA) ok = 0;
  643.  
  644.                 ddev->Ch_Regs[0].AddCmp.AddrComp0 = 0x55;
  645.                 if (ddev->Ch_Regs[0].AddCmp.AddrComp0 != 0x55) ok = 0;
  646.  
  647.                 ddev->System.sys_control.RESET = 1;
  648.                 while (ddev->System.sys_control.RESET && --timecount)
  649.                         ; /* Wait it to finish */
  650.                 if (timecount == 0) ok = 0;
  651.  
  652.                 if (ddev->Ch_Regs[0].AddCmp.AddrComp0 != 0) ok = 0;
  653.  
  654.                 if (!ok)
  655.                         break;
  656.                         /* No DDLC chip found.. */
  657.  
  658.                 /* Did set the chip into a known state.. */
  659.  
  660.                 /* Configure serial channels into Packet-Modem -style
  661.                    interfaces */
  662.                 ddev->Ch_Regs[0].SerControl.serial_control.MODE = 0x8;
  663.                 ddev->Ch_Regs[1].SerControl.serial_control.MODE = 0x8;
  664.  
  665.                 /* Now enable proper Interrupts ..*/
  666.                 ddev->Interrupt.IntEn = 0; /* First disable them all.. */
  667.                 /* Enable needed ones with channel attaches */
  668.  
  669.                 ++ddev; /* Next device if nchips is 2.. */
  670.                 ++nchips;
  671.         }
  672.  
  673.         if (nchips == 0) {
  674.                 printf("DDLC chip not found at 0x%05lX.  \"attach ddlc init\" failed!\n",
  675.                         (((long)FP_SEG(boardbase))<<4)+(long)FP_OFF(boardbase));
  676.                 return -1;
  677.         }
  678.  
  679.  
  680.         cfgval = 03 & *((char*)boardbase + CONFIGREG);
  681.  
  682.         if (cfgval == 3 && memsize == 0) {
  683.                 printf("DDLC: memsize param missing; No config read register on this board version.\n");
  684.         return -1;
  685.     }
  686.  
  687.         if (memsize == 0) {
  688.                 /* Sniff the size of the buffer memory */
  689.                 if (1 & cfgval)
  690.                         memsize = 32*1024;
  691.                 else
  692.                         memsize = 16*1024;
  693.         }
  694.  
  695.         /* Reset (zero) the buffer memory */
  696.         memset(boardbase+MEMSTART,0,memsize-MEMSTART);
  697.  
  698.  
  699.         Ddlc[boardnum].channelcnt       = nchips << 1; /* *2 */ /* XX: LOG_CHANNELS_ON_BOARD ? */
  700.         Ddlc[boardnum].vec              = ivec;
  701.         Ddlc[boardnum].ints             = 0L;
  702.         Ddlc[boardnum].dtrreg           = 0xFF; /* All lines high.. */
  703.         Ddlc[boardnum].boardbase        = boardbase;
  704.         Ddlc[boardnum].boardsize        = memsize;
  705.         Ddlc[boardnum].oldvec           = getirq(ivec);
  706.         Ddlc[boardnum].nextfreebuf      = boardbase + MEMSTART; /* SRAM start */
  707.         Ddlc[boardnum].bufavail         = memsize   - MEMSTART;
  708.  
  709.     *(boardbase+DTRREG) = Ddlc[boardnum].dtrreg;
  710.  
  711.         DISABLE();
  712.         maskon(ivec);
  713.         RESTORE();
  714.  
  715.         setirq(ivec,Ddlc_handle[boardnum]);
  716.         return 0;
  717. }
  718.  
  719. /*
  720.  * Attach a DDLC interface to the system
  721.  * argv[0]: hardware type, must be "ddlc"
  722.  * argv[1]: "init" - a special case telling about boards
  723.  *          Max insertation is  DDLCMAX -boards (2 by default)
  724.  *  argv[2]: io-base-address (memory-mapped board)
  725.  *  argv[3]: IRQ vector number
  726.  *  argv[4]: (OPTIONAL!) memory size -- 16kB/32kB (first char is checked)
  727.  * else:
  728.  * argv[1]: channel nbr: 0..3 in the first board, 4..7 in the next, etc.
  729.  * argv[2]: mode, one of: "ax25", "raw", "hdlc"
  730.  * argv[3]: interface label, e.g., "dd0"
  731.  * argv[4]: maximum transmission unit, bytes (MTU)
  732.  * argv[5]: Informative guess of interface speed (9600/56000/64000/1E6/...)
  733.  *          this is listed in status, but does not affect links.
  734.  * argv[6]: Duplex-type: "f" or "h" (by first char)
  735.  * argv[7]: Interface IP address, optional (defaults to Ip_addr);
  736.  */
  737. int
  738. ddlc_attach(argc,argv)
  739. int argc;
  740. char *argv[];
  741. {
  742. #ifdef  AX25
  743.         int rawencoding = 0;
  744. #endif
  745.         int channel, board, mtu, duplex, rc;
  746.         struct iface *if_h;
  747.         struct ddlcchan *ddch;
  748.         DDLC    *ddev;
  749.         CH_REGS *ddevch;
  750.         int32 addr1 = 0L;
  751.         char *baseaddr, *cp;
  752.  
  753.  
  754.         if (strcmp(argv[1],"init")==0) {
  755.                 int   vecnum;
  756.                 int32 baseaddr;
  757.                 unsigned int memsize = 0;
  758.  
  759.  
  760.                 if (argc < 4/*3+1*/ || argc > 5/*4+1*/) {
  761.                         printf("Bad  attach ddlc init -command. Wrong arg count.\n");
  762.                         return -1;
  763.                 }
  764.                 if (boardcnt >= DDLCMAX) {
  765.                         printf("Too many DDLC adapters\n");
  766.                         return -1;
  767.                 }
  768.                 board = boardcnt++;
  769.                 baseaddr = htol(argv[2]);
  770.                 if ((baseaddr < 0xA0000) ||  (baseaddr >= 0xFC000)) {
  771.                         printf("Adapter base address is bad.  Must be in range 0xA0000 - 0xFC000\n"
  772.                                " You gave: `%s'\n",argv[2]);
  773.                         return -1;
  774.                 }
  775.                 baseaddr <<= 12; /* XX: Very PC-specific, but so is the card too..*/
  776.                 vecnum = atoi(argv[3]);
  777.                 if (vecnum < 2 || vecnum > 7) {
  778.                         printf("INT vector (`%s') bad for the DDLC board. Must be in range 2..7\n",argv[4]);
  779.                         return -1;
  780.                 }
  781.                 if (argc == 5) {
  782.                         if (*argv[4] != '1' && *argv[4] != '3') {
  783.                                 printf("optional MEMSIZE argument is bad: `%s'   If given, must be 16kB or 32kB\n",argv[4]);
  784.                         }
  785.                         memsize = 32*1024;
  786.                         if (*argv[4] == '1')
  787.                             memsize = 16*1024;
  788.                 }
  789.  
  790.                 rc = ddlc_init( board, (char*)baseaddr, vecnum, memsize);
  791.                 if (rc == -1) --boardcnt;
  792.                 return rc;
  793.         }
  794.  
  795.         if (argc < 7 || argc > 8+1) {
  796.                 printf("too few or too many arguments\n");
  797.                 return -1;
  798.         }
  799.         channel = atoi(argv[1]);
  800.         board = channel >> LOG_CHANNELS_ON_BOARD;
  801.         if (channel < 0 || board >= boardcnt) {
  802.                 printf("No attached card for given channel %d\n",channel);
  803.                 return -1;
  804.         }
  805.         /* XX: CHANNELS_ON_BOARD ? */
  806.         if (Ddlc[board].channelcnt == 2 &&
  807.             (channel & 3) > 1) {
  808.                 printf("only 2 channels on this card (board:%d)\n",board);
  809.                 return -1;
  810.         }
  811.         if (Ddlc[board].attachlog & (1 << (channel & (CHANNELS_ON_BOARD - 1)))) {
  812.                 printf("channel %d has already been attached.\n",channel);
  813.                 return -1;
  814.         }
  815. #ifdef  AX25
  816.         if (stricmp(argv[2],"ax25")==0) {
  817.                 rawencoding = 0;
  818.                 if (Mycall[0] == '\0') {
  819.                         printf("set mycall for AX25 first\n");
  820.                         return -1;
  821.                 }
  822.         } else
  823. #endif
  824.             if (stricmp(argv[2],"raw")==0 ||
  825.                  stricmp(argv[2],"hdlc")==0)
  826. #ifdef  AX25
  827.                 rawencoding = 1;
  828. #else
  829.                 ;
  830. #endif
  831.         else {
  832.                 printf("Bad encapsulation format: `%s'\n  "
  833. #ifdef  AX25
  834.                        "AX25, and "
  835. #endif
  836.                        "HDLC (alias RAW) supported\n",
  837.                        argv[2]);
  838.                 return -1;
  839.         }
  840.         if (if_lookup(argv[3]) != NULLIF) {
  841.                 printf("Interface %s already exists\n",argv[3]);
  842.                 return -1;
  843.         }
  844.         if ((mtu = atoi(argv[4])) < 64 || mtu > 4095) {
  845.                 printf("MTU value `%s' invalid\n",argv[4]);
  846.                 return -1;
  847.         }
  848.         if (*argv[6] != 'f' && *argv[6] != 'h') {
  849.                 printf("Duplex value `%s' is bad.  Use `half' or `full'\n",argv[6]);
  850.                 return -1;
  851.         }
  852.         duplex = (*argv[6] == 'f');
  853.         addr1 = Ip_addr;
  854.         if (argc > 7)
  855.                 addr1 = resolve(argv[7]);
  856.         if (addr1 == 0L) {
  857.                 printf(Noipaddr);
  858.                 return -1;
  859.         }
  860.  
  861.         /* Create new interface structure */
  862.         if_h = (struct iface *) callocw(1,sizeof(struct iface));
  863.         if_h->addr      = addr1;
  864.         if_h->name      = strdup(argv[3]);
  865.         if_h->mtu       = mtu;
  866.         if_h->ioctl     = ddlc_ctl;
  867.         if_h->dev       = channel;
  868.         if_h->stop      = ddlc_stop;
  869.         if_h->raw       = ddlc_raw;
  870.         ddch = &Ddlcchan[channel];
  871.         ddch->iface     = if_h;
  872.         if (ddch->speed) free(ddch->speed);
  873.         ddch->speed     = strdup(argv[5]);
  874.         ddch->Board     = &Ddlc[board];
  875.  
  876.         ddch->bufsiz    = mtu;
  877.         ddch->rcp1      = ddlc_buf_alloc(ddch,2);
  878.         ddch->rcp2      = ddlc_buf_alloc(ddch,2);
  879.         ddch->txp1      = ddlc_buf_alloc(ddch,0);
  880.         ddch->txp2      = ddlc_buf_alloc(ddch,0);
  881.         ddch->rxside    = 0;
  882.         ddch->txside    = 0;
  883.  
  884.         if (!ddch->txp2) {
  885.                 /* Buffer allocation failure, free all allocated data.. */
  886.                 printf("Out of interface buffer memory on channel `%s'\n",
  887.                        if_h->name);
  888.                 ddlc_buf_purge(ddch);
  889.                 free(ddch->speed);
  890.                 ddch->speed = NULL;
  891.                 free(if_h->name);
  892.                 free(if_h);
  893.                 return -1;
  894.         }
  895.  
  896.         /* Init DDLC frame registers */
  897.  
  898.         ddev = (DDLC *)(ddch->Board->boardbase);
  899.         if (2 & channel) ++ddev; /* on the 2nd chip of the board */
  900.         ddevch = & ddev->Ch_Regs[channel & 1];
  901.         cputw(&ddevch->RxBufLen,mtu);
  902.         cputw(&ddevch->TxFrLen, 0);
  903.         baseaddr = ddch->Board->boardbase;
  904.         cputw(&ddevch->RxABase, (int16)(ddch->rcp1 - baseaddr));
  905.         cputw(&ddevch->RxBBase, (int16)(ddch->rcp2 - baseaddr));
  906.         ddch->TxAbase = ddch->txp1 - baseaddr;
  907.         ddch->TxBbase = ddch->txp2 - baseaddr;
  908.  
  909.         /* Store other operative data */
  910.  
  911.         ddch->dev        = channel;
  912.         ddch->unit       = channel % 4;
  913.         ddch->duplex     = duplex;
  914.         ddch->tstate     = IDLE;
  915.         ddch->rstate     = ACTIVE;
  916.         /* default channel access Params */
  917.         ddch->txdelay    =   5;         /*  50 ms */
  918.         ddch->persist    = 128;         /*  50% persistance */
  919.         ddch->slotime    =  30;         /* 300 ms */
  920.         ddch->squeldelay =   3;         /*  30 ms */
  921.  
  922. #ifdef AX25
  923.         if (rawencoding)
  924.                 setencap(if_h,"HDLC");
  925.         else {
  926.                 setencap(if_h,"AX25");
  927.                 if (if_h->hwaddr == NULLCHAR)
  928.                         if_h->hwaddr = mallocw(AXALEN);
  929.                 memcpy(if_h->hwaddr,Mycall,AXALEN);
  930.         }
  931. #else
  932.         setencap(if_h,"HDLC"); /* No choise - only raw HDLC framing */
  933. #endif
  934.  
  935.         /* Link the interface into the interface list */
  936.         if_h->next = Ifaces;
  937.         Ifaces = if_h;
  938.  
  939.         /* Initialize the defer timer */
  940.         ddch->defer.func = (void *)ddlc_txintdefer;
  941.         ddch->defer.arg  = ddch;
  942.         set_timer(&ddch->defer,MSPTICK);
  943.  
  944.         cp = if_name(if_h, " tx");
  945.         if_h->txproc = newproc(cp,512,if_tx,0,if_h,NULL,0);
  946.         free(cp);
  947.  
  948. #define DINT ddev->Interrupt.int_enable
  949.         if ((channel & 1) == 0) {
  950.                 /* Chip channel 0, Interrupt enables ON */
  951.                 /* If duplex channel, use DMA Complete interrupts to
  952.                    indicate frame completition. Then queue next frame
  953.                    to be sent...  For radio-channels, use Frame Complete
  954.                    interrupt which tells when sent frame is finished from
  955.                    transmitter */
  956.                 if (ddch->duplex)
  957.                         DINT.Tx0DMAC    = 1;
  958.                 else
  959.                         DINT.Tx0FC      = 1;
  960.                 DINT.Rx0DMAC    = 1;
  961.                 DINT.Rx0Idl     = 1;
  962.                 DINT.CD0        = 1;
  963.         } else {
  964.                 /* Chip channel 1, Interrupt enables ON */
  965.                 if (ddch->duplex)
  966.                         DINT.Tx1DMAC    = 1;
  967.                 else
  968.                         DINT.Tx1FC      = 1;
  969.                 DINT.Rx1DMAC    = 1;
  970.                 DINT.Rx1Idl     = 1;
  971.                 DINT.CD1        = 1;
  972.         }
  973.         cputw(&ddevch->RxCont.RxCntr, 0);
  974.         ddevch->RxCont.rx_control.BAR = 1; /* Start with buffer A active */
  975.         cputw(&ddevch->RxCont.RxCntr, 0);
  976.         cputw(&ddevch->TxCont.TxCntr, 0);
  977. #undef DINT
  978.  
  979.         Ddlc[board].attachlog |= 1 << (channel & 3); /* Mark up that this has been attached */
  980.         return 0;
  981. }
  982.  
  983. /* SET Transmit or Receive Mode
  984.  * Set RTS (request-to-send) to modem on Transmit
  985.  */
  986. static void
  987. ddlc_rts(ddch, x)
  988. register struct ddlcchan *ddch;
  989. int16 x;
  990. {
  991.         int   unit = ddch->unit;
  992.         int   chan = unit & 1;
  993.         DDLC *ddev = (DDLC*)(ddch->Board->boardbase)[unit >> 1];
  994.  
  995.         /* Turn on the transmitter to send flags */
  996.         if(x == ON){    /* Turn Tx ON */
  997.                 if (ddch->duplex == 0) { /* Half-duplex.. */
  998.                         /* .. also turn the receiver OFF */
  999.                         ddev->Ch_Regs[chan].RxCont.rx_control.RE = 0;
  1000.                         ddch->rstate = IDLE;
  1001.                 }
  1002.                 ddev->Ch_Regs[chan].TxCont.tx_control.TE = 1;
  1003.                 /* Transmitter now on */
  1004.         } else {        /* Tx OFF and Rx ON */
  1005.                 ddch->tstate = IDLE;
  1006.                 ddch->rstate = ACTIVE; /* Normal state */
  1007.                 ddev->Ch_Regs[chan].RxCont.rx_control.RE = 1;
  1008.                 ddev->Ch_Regs[chan].TxCont.tx_control.TE = 0;
  1009.  
  1010.                 /* setup_ddlc_rx_dma(ddch); */
  1011.                 /* Hold tx off long enough for other station to reply */
  1012.                 ddch->deftime = msclock() + ddch->txdelay + 100; /* XX: values?? */
  1013.         }
  1014.         return;
  1015. }
  1016.  
  1017.  
  1018. /* Subroutine to set KISS params in channel tables */
  1019. static int32
  1020. ddlc_ctl(iface, cmd, set, val)
  1021. struct iface *iface;
  1022. int cmd;
  1023. int set;
  1024. int32 val;
  1025. {
  1026.         struct ddlcchan *ddch;
  1027.         int32 t,ca;
  1028.         int16 i;
  1029.         DDLC *ddev;
  1030.         CH_REGS *ddevch;
  1031.         int16 channel, unit;
  1032.  
  1033.         channel = iface->dev;
  1034.         ddch   = &Ddlcchan[ channel ]; /* point to channel table */
  1035.         unit    = ddch->unit;
  1036.         ddev   = (DDLC*)ddch->Board->boardbase;
  1037.         ddevch = & ddev->Ch_Regs[unit & 1];
  1038.         if (unit & 2)
  1039.                 ++ddevch;
  1040.  
  1041.         switch(cmd){
  1042.         case PARAM_DATA: /* XX: ?? */
  1043.                 break;
  1044.         case PARAM_TXDELAY:
  1045.                 if(set)
  1046.                         ddch->txdelay = val;
  1047.                 return ddch->txdelay;
  1048.         case PARAM_PERSIST:
  1049.                 if(set)
  1050.                         ddch->persist = val;
  1051.                 return uchar(ddch->persist);
  1052.         case PARAM_SLOTTIME:
  1053.                 if(set)
  1054.                         ddch->slotime = val;
  1055.                 return ddch->slotime;
  1056.         case PARAM_TXTAIL:
  1057.                 if(set)
  1058.                         ddch->squeldelay = val;
  1059.                 return ddch->squeldelay;
  1060.         case PARAM_FULLDUP:
  1061.                 if (set)
  1062.                         if (ddch->duplex != val) {
  1063.                                 /* XX: Alter interrupt register usage! */
  1064.                                 ddch->duplex = val;
  1065.                         }
  1066.                 return ddch->duplex;
  1067.         case PARAM_HW: /* XX: ?? */
  1068.                 break;
  1069.         case PARAM_MUTE:
  1070.                 if(set){
  1071.                         if(val == -1){
  1072.                                 /* Special case for duration of a CTS */
  1073.                                 val = ddch->txdelay + 500;
  1074.                         }
  1075.                         ddch->deftime = msclock() + val;
  1076.                 }
  1077.                 t = msclock();
  1078.                 ca = ddch->deftime - t;
  1079.                 if(ca < 0){
  1080.                         ddch->deftime = t;
  1081.                         ca = 0;
  1082.                 }
  1083.                 return ca;
  1084.         case PARAM_DTR:         /* DTR value setup, REMEMBER: LOW ACTIVE */
  1085.                 i = 1 << (4 + unit);
  1086.                 if (set) {
  1087.                         if (val==0)
  1088.                                 ddch->Board->dtrreg |= i;
  1089.                         else
  1090.                                 ddch->Board->dtrreg &= ~i;
  1091.                         *((unsigned char*)(ddch->Board->boardbase) + DTRREG) =
  1092.                                 ddch->Board->dtrreg;
  1093.                 }
  1094.                 return !(i & ddch->Board->dtrreg);
  1095.         case PARAM_RTS:         /* XX: ?? */
  1096.                 if (set) {
  1097.                         DISABLE(); /* ?? Taken from those previous models..
  1098.                                  This chip might not need these */
  1099.                         ddevch->TxCont.tx_control.TE = val;
  1100.                         RESTORE();
  1101.                 }
  1102.                 return ddevch->TxCont.tx_control.TE;
  1103.         case PARAM_SPEED:       /* XX: ?? */
  1104.                 break;
  1105.         case PARAM_ENDDELAY:    /* XX: ?? */
  1106.                 if (set)
  1107.                         ddch->enddelay = val;
  1108.                 return ddch->enddelay;
  1109.         case PARAM_GROUP:       /* XX: ?? */
  1110.                 if (set)
  1111.                         ddch->group = val;
  1112.                 return ddch->group;
  1113.         case PARAM_IDLE:        /* XX: ?? */
  1114.                 if (set)
  1115.                         ddch->idletime = val;
  1116.                 return ddch->idletime;
  1117.         case PARAM_MIN:         /* XX: ?? */
  1118.                 if (set)
  1119.                         ddch->mintime = val;
  1120.                 return ddch->mintime;
  1121.         case PARAM_MAXKEY:      /* XX: ?? */
  1122.                 if (set)
  1123.                         ddch->maxkeyup = val;
  1124.                 return ddch->maxkeyup;
  1125.         case PARAM_WAIT:        /* XX: ?? */
  1126.                 if (set)
  1127.                         ddch->waittime = val;
  1128.                 return ddch->waittime;
  1129.         case PARAM_DOWN:        /* XX: ?? */
  1130.                 break;
  1131.         case PARAM_UP:          /* XX: ?? */
  1132.                 break;
  1133.         case PARAM_BLIND:       /* XX: ?? */
  1134.                 break;
  1135.         case PARAM_RETURN:      /* XX: ?? */
  1136.                 break;
  1137.         default:
  1138.                 break;
  1139.         }
  1140.         return -1;
  1141. }
  1142.  
  1143.  
  1144. static int
  1145. ddlc_stop(iface)
  1146. struct iface *iface;
  1147. {
  1148.         int channel = iface->dev;
  1149.         struct ddlcchan *ddch = &Ddlcchan[channel];
  1150.         int chipchannel = 1 & channel;
  1151.         DDLC *ddev = &((DDLC*)(ddch->Board->boardbase))[1 & (channel >> 1)];
  1152.  
  1153.         if (!(ddch->Board->attachlog & (1 << (channel & 3)))) {
  1154.                 return -1;
  1155.         }
  1156.         DISABLE();
  1157.  
  1158.         /* Disable interrupts related to specified channel */
  1159. #define DINT ddev->Interrupt.int_enable
  1160.         if (chipchannel == 0) {
  1161.                 /* Chip channel 0, Interrupt enables off */
  1162.                 DINT.Tx0FC      = 0;
  1163.                 DINT.Tx0DMAC    = 0;
  1164.                 DINT.Rx0DMAC    = 0;
  1165.                 DINT.Rx0Idl     = 0;
  1166.                 DINT.CD0        = 0;
  1167.         } else {
  1168.                 /* Chip channel 1, Interrupt enables off */
  1169.                 DINT.Tx1FC      = 0;
  1170.                 DINT.Tx1DMAC    = 0;
  1171.                 DINT.Rx1DMAC    = 0;
  1172.                 DINT.Rx1Idl     = 0;
  1173.                 DINT.CD1        = 0;
  1174.         }
  1175.         cputw(&ddev->Ch_Regs[chipchannel].RxCont.RxCntr, 0);
  1176.         cputw(&ddev->Ch_Regs[chipchannel].TxCont.TxCntr, 0);
  1177. #undef DINT
  1178.  
  1179.     RESTORE();
  1180.         ddlc_buf_purge(ddch);
  1181.  
  1182.         ddch->Board->attachlog &= ~(1 << (channel & 3));
  1183.  
  1184.         /* XX: Do necessary DDLC shutdown things on ONE channel         */
  1185.         /* XX: If no more channels on that board, detach the board ???  */
  1186. #if 0
  1187.     DISABLE();
  1188.         /* mask off interrupt input */
  1189.         maskoff(ddch->vec);
  1190.  
  1191.         /* restore original interrupt vector */
  1192.         setirq(ddch->vec, ddch->oldvec);
  1193.         RESTORE();
  1194. #endif
  1195.         return 0;
  1196. }
  1197.  
  1198. int
  1199. ddlcstop()
  1200. {
  1201.         return 0;
  1202. }
  1203.  
  1204.  
  1205. /* Send raw packet on DDLC interface */
  1206. static int
  1207. ddlc_raw(iface,bp)
  1208. struct iface *iface;
  1209. struct mbuf  *bp;
  1210. {
  1211.         struct ddlcchan *ddch = &Ddlcchan[iface->dev];
  1212.  
  1213.         enqueue(&ddch->sndq, bp);
  1214.  
  1215.         /* See if anything is being transmitted */
  1216.         if (ddch->tstate == IDLE)
  1217.                 ddlc_txintdefer(ddch);
  1218.         return 0;
  1219. }
  1220.  
  1221.  
  1222. /*
  1223. static void
  1224. setup_ddlc_rx_dma(ddch)
  1225. struct ddlcchan *ddch;
  1226. {
  1227. }
  1228.  
  1229. static void
  1230. setup_ddlc_tx_dma(ddch, buffer, length)
  1231. struct ddlcchan *ddch;
  1232. char *buffer;
  1233. int length;
  1234. {
  1235. }
  1236. */
  1237.  
  1238. static void
  1239. tdelay(ddch, time)
  1240. register struct ddlcchan *ddch;
  1241. unsigned int time;
  1242. {
  1243. }
  1244.  
  1245.  
  1246. /* XX: Hanged into generic timer queue for whatever use.. */
  1247. int
  1248. ddlctimer()
  1249. {
  1250.     return 0;
  1251. }
  1252.  
  1253.  
  1254.  
  1255. static int
  1256. buf_ptr_name(s,board,buf)
  1257. char **s;
  1258. const int board;
  1259. char far *buf;
  1260. {
  1261.     int i;
  1262.     struct ddlcchan *ddch = &Ddlcchan[ board << 2 ];
  1263.  
  1264.     buf += 2; /* Adjust it to be to a buffer block */
  1265.  
  1266.     for (i=0; i<4; ++i) {
  1267.         if (!ddch->iface) continue; /* Not attached */
  1268.         if ((ddch->rcp1) == buf) { *s = "Rcp1"; return ddch->dev; }
  1269.         if ((ddch->rcp2) == buf) { *s = "Rcp2"; return ddch->dev; }
  1270.         if ((ddch->txp1) == buf) { *s = "Txp1"; return ddch->dev; }
  1271.         if ((ddch->txp2) == buf) { *s = "Txp2"; return ddch->dev; }
  1272.         ++ddch;
  1273.     }
  1274.     *s = "Unknown";
  1275.     return -1;
  1276. }
  1277.  
  1278.  
  1279. /* Various feature commands for this card:
  1280.     ddlc stat <board>
  1281.     ...
  1282. */
  1283. static int doddlc_stat __ARGS((const int, const char **));
  1284. static int
  1285. doddlc_stat(argc,argv)
  1286. const int argc;
  1287. const char *argv[];
  1288. {
  1289.     volatile int16 *buf, *memend;
  1290.     int i, board = -1;
  1291.     int lastchan;
  1292.     struct ddlcchan *ddch;
  1293.     struct DDLCTAB *Board = NULL;
  1294.  
  1295.     board = atoi(argv[2]);
  1296.     if (board < 0 ||
  1297.         board >= boardcnt) {
  1298.         printf("No such DDLC board `%s'\n",argv[2]);
  1299.         return -1;
  1300.     }
  1301.     Board = &Ddlc[board];
  1302.  
  1303.     buf    = (int16*)(Board->boardbase + MEMSTART);
  1304.     memend = (int16*)(Board->boardbase + Board->boardsize);
  1305.     printf("Board:\n");
  1306.     printf("  base addr = %04X:%04X",FP_SEG(Board->boardbase),
  1307.                  FP_OFF(Board->boardbase));
  1308.     printf("  IRQ = %d",Board->vec);
  1309.     printf("  Channel count = %d",Board->channelcnt);
  1310.     printf("  Attached channels: ");
  1311.     for (i=0;i<4;++i) {
  1312.         if ((1 << i) & Board->attachlog)
  1313.             printf("%d ",i);
  1314.     }
  1315.     if (Board->attachlog == 0)
  1316.         printf("none");
  1317.  
  1318.     printf("\n");
  1319.     printf("  memory size = %ld (0x%04lX)",
  1320.         (unsigned long)Board->boardsize,
  1321.         (unsigned long)Board->boardsize);
  1322.     printf("  bufavail = %ld",(unsigned long)Board->bufavail);
  1323.     printf("  nextfreebuf = 0x%04X (%d)\n",
  1324.         FP_OFF(Board->nextfreebuf),
  1325.         FP_OFF(Board->nextfreebuf));
  1326.     printf("Memory buffers:\n");
  1327.     if (*buf) {
  1328.         do {
  1329.             int16 val = *buf;
  1330.             int   chan;
  1331.             char  *s;
  1332.             printf(    "  0x%04X: %5d bytes - %s ",
  1333.                 FP_OFF(buf), val & ~BUF_IN_USE,
  1334.                 BUF_IN_USE & val ? "in use":"free  ");
  1335.             if (BUF_IN_USE & val) {
  1336.                 chan = buf_ptr_name(&s,board,buf);
  1337.                 printf("  owner: chan %d  %s",chan,s);
  1338.             }
  1339.             printf("\n");
  1340.             fflush(stdout);
  1341.             pwait(NULL);
  1342.             (char*)buf += ((val & ~BUF_IN_USE) +2);
  1343.         } while (*buf && (buf < memend));
  1344.     } else
  1345.         printf("  None in use!\n");
  1346.  
  1347.     if (*buf)
  1348.         printf(    "  0x%04X: %5d bytes - %s  -- outside memory!\n",
  1349.             FP_OFF(buf), *buf & ~BUF_IN_USE,
  1350.             BUF_IN_USE & *buf ? "in use":"free"),
  1351.         fflush(stdout),
  1352.         pwait(NULL);
  1353.     lastchan = (board+1) << LOG_CHANNELS_ON_BOARD;
  1354.     for (i=board << LOG_CHANNELS_ON_BOARD;i<lastchan;++i) {
  1355.         ddch = &Ddlcchan[ i ];
  1356.  
  1357.         printf("Channel:  %d  ",i);
  1358.         if (Board->channelcnt <= (i & (CHANNELS_ON_BOARD-1))) {
  1359.             printf("NOT PRESENT\n");
  1360.             continue;
  1361.         }
  1362.         if (Board->attachlog & (1 << ((CHANNELS_ON_BOARD-1) & i))) {
  1363.             printf("attached as `%s'\n",ddch->iface->name);
  1364.         } else {
  1365.             printf("not attached\n");
  1366.         }        
  1367.         printf("  rxints:   %4ld",  ddch->rxints);
  1368.         printf("  txints:  %4ld",   ddch->txints);
  1369.         printf("  exints: %4ld",    ddch->exints);
  1370.         printf("  enqueued: %4ld\n",ddch->enqueued);
  1371.         printf("  rxframes: %4ld",  ddch->rxframes);
  1372.         printf("  crcerrs: %4d",    ddch->crcerrs);
  1373.         printf("  rovers: %4d",     ddch->rovers);
  1374.         printf("  tunders:  %4d",   ddch->tunders);
  1375.         printf("  bufsiz: %4u\n",   ddch->bufsiz);
  1376.         printf("  RxAbase: 0x%04X", ddch->rcp1 - Board->boardbase);
  1377.         printf(" RxBbase: 0x%04X",  ddch->rcp2 - Board->boardbase);
  1378.         printf(" TxAbase: 0x%04X",  ddch->TxAbase);
  1379.         printf(" TxBbase: 0x%04X\n",ddch->TxBbase);
  1380.         fflush(stdout);
  1381.         pwait(NULL);
  1382.     }
  1383.     return 0;
  1384. }
  1385. static int doddlc_test __ARGS((void));
  1386. static int
  1387. doddlc_test()
  1388. {
  1389. #define TESTSIZ 10240
  1390.     char *s = (char*)malloc(TESTSIZ);
  1391.     char *b = Ddlc[0].boardbase + MEMSTART; /* Buffer start */
  1392.     if (boardcnt < 1) {
  1393.         printf("Sorry, board 0 has not been initialized!  Can't test!\n");
  1394.         return -1;
  1395.     }
  1396.  
  1397.     printf("Running buffer data movement tests,  838 ns/clock count.  Overflow at 55ms.\n");
  1398.     swstart();
  1399.     memcpy(s,b,TESTSIZ);
  1400.     swstop(0);
  1401.     printf("memcpy(ddlcbuf->coremem,%d), watch chan 0\n",TESTSIZ);
  1402.  
  1403.     swstart();
  1404.     memcpy(b,s,TESTSIZ);
  1405.     swstop(1);
  1406.     printf("memcpy(ddlcbuf<-coremem,%d), watch chan 1\n",TESTSIZ);
  1407.  
  1408.     free(s);
  1409.     return 0;
  1410. }
  1411.  
  1412. /* Some misc test/statistics commands from primary command "ddlc" */
  1413.  
  1414. int
  1415. do_ddlc(argc,argv)
  1416. int argc;
  1417. char *argv[];
  1418. {
  1419.     int i, ok = 1;
  1420.     enum {Cmd_None = -1, Cmd_Stat, Cmd_Test } cmd;
  1421.  
  1422.  
  1423.     cmd = Cmd_None;
  1424.     if (argc < 2)
  1425.         ok = 0;
  1426.  
  1427.     if (ok && stricmp(argv[1],"stat")==0 && argc == 3)
  1428.         cmd = Cmd_Stat;
  1429.     else if (ok && stricmp(argv[1],"test")==0 && argc == 2)
  1430.         cmd = Cmd_Test;
  1431.  
  1432.     if (!ok || cmd == Cmd_None) {
  1433.         printf("Usage:\tddlc stat <board>\n\tddlc test\n");
  1434.         return -1;
  1435.     }
  1436.     switch (cmd) {
  1437.         case Cmd_Stat:
  1438.             return doddlc_stat(argc,argv);
  1439.         case Cmd_Test:
  1440.             return doddlc_test();
  1441.         default:
  1442.             ;
  1443.     }
  1444.     printf("DDLC sub-command `%s' not implemented!\n",argv[1]);
  1445.     return -1;
  1446. }
  1447.